﻿using System.Linq;
using Fabrication.Exceptions;
using Fabrication.Tests.TestClasses;
using NUnit.Framework;

namespace Fabrication.Tests
{
    [TestFixture]
    public class boolean_rules
    {
        [Test]
        public void should_negate_boolean_values()
        {
            var builtItem = new FabricationScope().Setup<DoublePropertyClass<bool>>()
                            .For(x => x.FirstValue).Use(false)
                            .For(x => x.SecondValue).Negate(x => x.FirstValue)
                            .Generate();

            Assert.That(builtItem.SecondValue, Is.True);
        }

        [Test]
        public void should_fail_if_rule_negates_itself()
        {
            var options = new FabricationScope().Setup<DoublePropertyClass<bool>>();

            Assert.Throws<LinkedPropertyException>(() => options.For(x => x.FirstValue).Negate(x => x.FirstValue));
        }

        [Test]
        public void should_fail_if_rules_negate_each_other_directly()
        {
            var options = new FabricationScope().Setup<DoublePropertyClass<bool>>()
                            .For(x => x.FirstValue).Negate(x => x.SecondValue);

            Assert.Throws<LinkedPropertyException>(() => options.For(x => x.SecondValue).Negate(x => x.FirstValue));
        }

        [Test]
        public void should_fail_if_rules_negate_each_other_indirectly()
        {
            var options = new FabricationScope().Setup<TriplePropertyClass<bool>>()
                            .For(x => x.FirstValue).Negate(x => x.SecondValue)
                            .For(x => x.SecondValue).Negate(x => x.ThirdValue);

            Assert.Throws<LinkedPropertyException>(() => options.For(x => x.ThirdValue).Negate(x => x.FirstValue));
        }

        [Test]
        public void should_set_to_true_or_false_if_set_to_randomize()
        {
            var builtItems = new FabricationScope().Setup<DoublePropertyClass<bool>>()
                            .For(x => x.FirstValue).Randomize()
                            .Generate(50);

            var distinctValues = builtItems.Select(x => x.FirstValue).Distinct().Count();

            Assert.That(distinctValues, Is.EqualTo(2));
        }

        [Test]
        public void should_create_fairly_even_distribution_if_set_to_randomize()
        {
            var builtItems = new FabricationScope().Setup<DoublePropertyClass<bool>>()
                            .For(x => x.FirstValue).Randomize()
                            .Generate(500);

            var trueValues = builtItems.Count(x => x.FirstValue);

            Assert.That(trueValues, Is.LessThan(350));
        }
    }
}
